package tech.yixiyun.framework.kuafu.kits;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.getter.BasicTypeGetter;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.*;

/**
 * 该类是完全拷贝自Hutools框架的Dict类，只是觉得这个类名不好记。
 * 本来想用继承，但一些静态方法无法继承，只能出此下策。
 * 此类非我开发。
 */
public class Kv extends LinkedHashMap<String, Object> implements BasicTypeGetter<String> {
    private static final long serialVersionUID = 6135423866861206530L;
    static final float DEFAULT_LOAD_FACTOR = 0.75F;
    static final int DEFAULT_INITIAL_CAPACITY = 16;
    private boolean caseInsensitive;


    public static Kv createBy(String key, Object value) {
        return create().put(key, value);
    }

    public static Kv create() {
        return new Kv();
    }

    public static <T> Kv parse(T bean) {
        return create().parseBean(bean);
    }

    @SafeVarargs
    public static Kv of(Pair<String, Object>... pairs) {
        Kv Kv = create();
        Pair[] var2 = pairs;
        int var3 = pairs.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Pair<String, Object> pair = var2[var4];
            Kv.put((String)pair.getKey(), pair.getValue());
        }

        return Kv;
    }

    public static Kv of(Object... keysAndValues) {
        Kv Kv = create();
        String key = null;

        for(int i = 0; i < keysAndValues.length; ++i) {
            if (i % 2 == 0) {
                key = Convert.toStr(keysAndValues[i]);
            } else {
                Kv.put(key, keysAndValues[i]);
            }
        }

        return Kv;
    }

    public Kv() {
        this(false);
    }

    public Kv(boolean caseInsensitive) {
        this(16, caseInsensitive);
    }

    public Kv(int initialCapacity) {
        this(initialCapacity, false);
    }

    public Kv(int initialCapacity, boolean caseInsensitive) {
        this(initialCapacity, 0.75F, caseInsensitive);
    }

    public Kv(int initialCapacity, float loadFactor) {
        this(initialCapacity, loadFactor, false);
    }

    public Kv(int initialCapacity, float loadFactor, boolean caseInsensitive) {
        super(initialCapacity, loadFactor);
        this.caseInsensitive = caseInsensitive;
    }

    public Kv(Map<String, Object> m) {
        super((Map)(null == m ? new HashMap() : m));
    }

    public <T> T toBean(T bean) {
        return this.toBean(bean, false);
    }

    public <T> T toBeanIgnoreCase(T bean) {
        BeanUtil.fillBeanWithMapIgnoreCase(this, bean, false);
        return bean;
    }

    public <T> T toBean(T bean, boolean isToCamelCase) {
        BeanUtil.fillBeanWithMap(this, bean, isToCamelCase, false);
        return bean;
    }

    public <T> T toBeanWithCamelCase(T bean) {
        BeanUtil.fillBeanWithMap(this, bean, true, false);
        return bean;
    }

    public <T> T toBean(Class<T> clazz) {
        return BeanUtil.toBean(this, clazz);
    }

    public <T> T toBeanIgnoreCase(Class<T> clazz) {
        return BeanUtil.toBeanIgnoreCase(this, clazz, false);
    }

    public <T> Kv parseBean(T bean) {
        Assert.notNull(bean, "Bean class must be not null", new Object[0]);
        this.putAll(BeanUtil.beanToMap(bean));
        return this;
    }

    public <T> Kv parseBean(T bean, boolean isToUnderlineCase, boolean ignoreNullValue) {
        Assert.notNull(bean, "Bean class must be not null", new Object[0]);
        this.putAll(BeanUtil.beanToMap(bean, isToUnderlineCase, ignoreNullValue));
        return this;
    }

    public <T extends Kv> void removeEqual(T Kv, String... withoutNames) {
        HashSet<String> withoutSet = CollUtil.newHashSet(withoutNames);
        Iterator var4 = Kv.entrySet().iterator();

        while(var4.hasNext()) {
            Map.Entry<String, Object> entry = (Map.Entry)var4.next();
            if (!withoutSet.contains(entry.getKey())) {
                Object value = this.get(entry.getKey());
                if (null != value && value.equals(entry.getValue())) {
                    this.remove(entry.getKey());
                }
            }
        }

    }

    public Kv filter(String... keys) {
        Kv result = new Kv(keys.length, 1.0F);
        String[] var3 = keys;
        int var4 = keys.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String key = var3[var5];
            if (this.containsKey(key)) {
                result.put(key, this.get(key));
            }
        }

        return result;
    }

    public Kv set(String attr, Object value) {
        this.put(attr, value);
        return this;
    }

    public Kv setIgnoreNull(String attr, Object value) {
        if (null != attr && null != value) {
            this.set(attr, value);
        }

        return this;
    }

    public Object getObj(String key) {
        return super.get(key);
    }

    public <T> T getBean(String attr) {
        return this.get(attr, (T)null);
    }

    public <T> T get(String attr, T defaultValue) {
        Object result = this.get(attr);
        return result != null ? (T) result : defaultValue;
    }

    public String getStr(String attr) {
        return Convert.toStr(this.get(attr), (String)null);
    }

    public Integer getInt(String attr) {
        return Convert.toInt(this.get(attr), (Integer)null);
    }

    public Long getLong(String attr) {
        return Convert.toLong(this.get(attr), (Long)null);
    }

    public Float getFloat(String attr) {
        return Convert.toFloat(this.get(attr), (Float)null);
    }

    public Short getShort(String attr) {
        return Convert.toShort(this.get(attr), (Short)null);
    }

    public Character getChar(String attr) {
        return Convert.toChar(this.get(attr), (Character)null);
    }

    public Double getDouble(String attr) {
        return Convert.toDouble(this.get(attr), (Double)null);
    }

    public Byte getByte(String attr) {
        return Convert.toByte(this.get(attr), (Byte)null);
    }

    public Boolean getBool(String attr) {
        return Convert.toBool(this.get(attr), (Boolean)null);
    }

    public BigDecimal getBigDecimal(String attr) {
        return Convert.toBigDecimal(this.get(attr));
    }

    public BigInteger getBigInteger(String attr) {
        return Convert.toBigInteger(this.get(attr));
    }

    public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) {
        return Convert.toEnum(clazz, this.get(key));
    }

    public byte[] getBytes(String attr) {
        return (byte[])this.get(attr, (Object)null);
    }

    public Date getDate(String attr) {
        return (Date)this.get(attr, (Object)null);
    }

    public Time getTime(String attr) {
        return (Time)this.get(attr, (Object)null);
    }

    public Timestamp getTimestamp(String attr) {
        return (Timestamp)this.get(attr, (Object)null);
    }

    public Number getNumber(String attr) {
        return (Number)this.get(attr, (Object)null);
    }

    public Object get(Object key) {
        return super.get(this.customKey((String)key));
    }

    public Kv put(String key, Object value) {
         super.put(this.customKey(key), value);
         return this;
    }

    public void putAll(Map<? extends String, ?> m) {
        m.forEach(this::put);
    }

    public Kv clone() {
        return (Kv)super.clone();
    }

    private String customKey(String key) {
        if (this.caseInsensitive && null != key) {
            key = key.toLowerCase();
        }

        return key;
    }

}
